package com.ruicar.afs.cloud.account.common.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruicar.afs.cloud.account.common.condition.AccountVoucherInfoCondition;
import com.ruicar.afs.cloud.account.common.dto.AccountVoucherDto;
import com.ruicar.afs.cloud.account.common.dto.AccountVoucherInfoDto;
import com.ruicar.afs.cloud.account.common.entity.AccountVoucherEntry;
import com.ruicar.afs.cloud.account.common.entity.AccountVoucherInfo;
import com.ruicar.afs.cloud.account.common.mapper.AccountVoucherInfoMapper;
import com.ruicar.afs.cloud.account.common.service.AccountVoucherEntryService;
import com.ruicar.afs.cloud.account.common.service.AccountVoucherInfoService;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.query.QueryCondition;
import com.ruicar.afs.cloud.common.core.uid.UidGenerator;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.WhetherEnum;
import com.ruicar.afs.cloud.common.modules.contract.enums.VoucherSendStatus;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author infinity
 * @version 1.0
 * @date 2020/7/5 19:18
 */
@Service
@AllArgsConstructor
public class AccountVoucherInfoServiceImpl extends ServiceImpl<AccountVoucherInfoMapper, AccountVoucherInfo> implements AccountVoucherInfoService {
    private final AccountVoucherEntryService accountVoucherEntryService;
    private UidGenerator uidGenerator;

    @Override
    public AccountVoucherInfoDto getVoucherInfo(Long id) {
        AccountVoucherInfoDto dto = new AccountVoucherInfoDto();
        AccountVoucherInfo info = this.getById( id );
        dto.setAccountVoucherInfo( info );
        dto.setEntryList( accountVoucherEntryService.list( Wrappers.<AccountVoucherEntry>query().lambda().eq( AccountVoucherEntry::getVoucherNo, info.getVoucherNo() ).orderByAsc( AccountVoucherEntry::getEntryNo ) ) );
        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean reversal(Long id) {
        AccountVoucherInfo infoHis = this.getById( id );
        Assert.isTrue( infoHis != null, "凭证信息不存在！" );
        Assert.isTrue( VoucherSendStatus.SEND_SUCCESS.equals( infoHis.getStatus() ), MessageFormat.format( "凭证状态不为：{0},凭证信息不可冲销!", AfsEnumUtil.desc( VoucherSendStatus.SEND_SUCCESS ) ) );
        Assert.isTrue( AfsEnumUtil.key( WhetherEnum.NO ).equals( infoHis.getReversalVoucherNo() ), "凭证信息已冲抵，不可重复！" );
        AccountVoucherInfo info = new AccountVoucherInfo();
        BeanUtil.copyProperties( infoHis, info, "createBy", "createTime", "id" );
        info.setStatus( VoucherSendStatus.NOT_SEND );
        info.setVoucherNo( this.getVoucherNo() );
        info.setVoucherSerialNumber( info.getVoucherNo() );
        info.setPostingDate( new Date() );
        info.setPreparedDate( new Date() );
        info.setTotalAmount( info.getTotalAmount().negate() );
        info.setReversalVoucherNo( AfsEnumUtil.key( WhetherEnum.NO ) );
        infoHis.setReversalVoucherNo( info.getVoucherNo() );
        infoHis.setStatus( VoucherSendStatus.RED );
        this.updateById( infoHis );
        this.save( info );

        List<AccountVoucherEntry> list = accountVoucherEntryService.list( Wrappers.<AccountVoucherEntry>query().lambda().eq( AccountVoucherEntry::getVoucherNo, infoHis.getVoucherNo() ).orderByAsc( AccountVoucherEntry::getEntryNo ) );
        BigDecimal creditAmt = BigDecimal.ZERO;
        BigDecimal debitAmt = BigDecimal.ZERO;
        for (AccountVoucherEntry accountVoucherEntry : list) {
            accountVoucherEntry.setId( null );
            accountVoucherEntry.setCreditAmt( accountVoucherEntry.getCreditAmt().negate() );
            accountVoucherEntry.setDebitAmt( accountVoucherEntry.getDebitAmt().negate() );
            creditAmt = creditAmt.add( accountVoucherEntry.getCreditAmt() );
            debitAmt = debitAmt.add( accountVoucherEntry.getDebitAmt() );
            accountVoucherEntry.setVoucherNo( info.getVoucherNo() );
            accountVoucherEntry.setCreateBy( null );
            accountVoucherEntry.setCreateTime( null );
            accountVoucherEntry.setUpdateBy( null );
            accountVoucherEntry.setUpdateTime( null );
        }
        Assert.isTrue( creditAmt.compareTo( debitAmt ) == 0, MessageFormat.format( "凭证流水号:[{0}]凭证借贷不平，不可冲销！", infoHis.getVoucherSerialNumber() ) );
        accountVoucherEntryService.saveBatch( list );
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean resend(Long id) {
        AccountVoucherInfo info = this.getById( id );
        Assert.isTrue( info != null, "凭证信息不存在！" );
        Assert.isTrue( VoucherSendStatus.SEND_FAIL.equals( info.getStatus() ), MessageFormat.format( "凭证状态不为：{0},凭证信息不可重新发送凭证信息!", AfsEnumUtil.desc( VoucherSendStatus.SEND_FAIL ) ) );
        info.setStatus( VoucherSendStatus.NOT_SEND );
        return this.updateById( info );
    }

    //获取凭证流水号
    public String getVoucherNo() {
        /**  生成凭证流水号  **/
        return DateUtil.format( new Date(), "dd" ) + uidGenerator.getUID();
    }

    public IPage getAccountVoucherInfoList(QueryCondition<AccountVoucherInfoCondition> condition) {
        IPage iPage = this.page( new Page<>( condition.getPageNumber(), condition.getPageSize() ),
                Wrappers.<AccountVoucherInfo>lambdaQuery()
                        .like( StringUtils.isNotBlank( condition.getCondition().getVoucherNo() ), AccountVoucherInfo::getVoucherNo,
                                condition.getCondition().getVoucherNo() != null ? condition.getCondition().getVoucherNo().trim() : condition.getCondition().getVoucherNo() )
                        .like( StringUtils.isNotBlank( condition.getCondition().getContractNo() ), AccountVoucherInfo::getContractNo,
                                condition.getCondition().getContractNo() != null ? condition.getCondition().getContractNo().trim() : condition.getCondition().getContractNo() )
                        .like( StringUtils.isNotBlank( condition.getCondition().getDealerName() ), AccountVoucherInfo::getDealerName,
                                condition.getCondition().getDealerName() != null ? condition.getCondition().getDealerName().trim() : condition.getCondition().getDealerName() )
                        .like( StringUtils.isNotBlank( condition.getCondition().getExplanation() ), AccountVoucherInfo::getExplanation,
                                condition.getCondition().getExplanation() != null ? condition.getCondition().getExplanation().trim() : condition.getCondition().getExplanation() )
                        .eq( condition.getCondition().getStatus() != null, AccountVoucherInfo::getStatus, condition.getCondition().getStatus() )
                        .ge( StringUtils.isNotBlank( condition.getCondition().getCreateStartDate() ), AccountVoucherInfo::getCreateTime, condition.getCondition().getCreateStartDate() )
                        .le( StringUtils.isNotBlank( condition.getCondition().getCreateEndDate() ), AccountVoucherInfo::getCreateTime,
                                StringUtils.isNotBlank( condition.getCondition().getCreateEndDate() ) ? DateUtil.endOfDay( DateUtil.parse( condition.getCondition().getCreateEndDate() ) ) : null )
                        .orderByDesc( AccountVoucherInfo::getCreateTime ) );
        return iPage;
    }

    @Override
    public List<AccountVoucherDto> exportVoucherList(QueryCondition<AccountVoucherInfoCondition> condition) {
        IPage iPage = this.getAccountVoucherInfoList( condition );
        List<AccountVoucherInfo> accountVoucherInfos = iPage.getRecords();
        if (CollectionUtil.isEmpty( accountVoucherInfos )) {
            return null;
        }
        List<AccountVoucherDto>  list =new ArrayList<>(  );
        for(AccountVoucherInfo accountVoucherInfo:accountVoucherInfos){
            List<AccountVoucherEntry> accountVoucherEntries = accountVoucherEntryService.list( Wrappers.<AccountVoucherEntry>query().lambda().eq( AccountVoucherEntry::getVoucherNo, accountVoucherInfo.getVoucherNo() ).orderByAsc( AccountVoucherEntry::getEntryNo ) );
            List<AccountVoucherDto>  accountVoucherDtos =  accountVoucherEntries.stream().map(accountVoucherEntry -> {
                AccountVoucherDto accountVoucherDto  =AccountVoucherDto.convertFromDto(accountVoucherInfo);;
                accountVoucherDto.setCreditAmt(accountVoucherEntry.getCreditAmt());
                accountVoucherDto.setDebitAmt(accountVoucherEntry.getDebitAmt());
                accountVoucherDto.setEntryNo(accountVoucherEntry.getEntryNo());
                accountVoucherDto.setExplanation(accountVoucherEntry.getExplanation());
                accountVoucherDto.setSubjectCode(accountVoucherEntry.getSubjectCode());
                accountVoucherDto.setSubjectName(accountVoucherEntry.getSubjectName());
                accountVoucherDto.setLendingDirection(AfsEnumUtil.desc(accountVoucherEntry.getLendingDirection()));
                return accountVoucherDto;
            }).collect(Collectors.toList());
            list.addAll(accountVoucherDtos) ;
        }
        return list;
    }


}
